﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;
using Ji.LinqHelper;

namespace Ji.BaseData
{
    /// <summary>
    /// 重写原有Prism中的NotificationObject
    /// </summary>
    [Serializable]
    public abstract class NotifyObject : INotifyPropertyChanged
    {
        /// <summary>
        /// Raised when a property on this object has a new value.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void RaisePropertyChanged(string propertyName = null)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// Raises this object's PropertyChanged event for each of the properties.
        /// </summary>
        /// <param name="propertyNames">The properties that have a new value.</param>
        protected void RaisePropertyChanged(params string[] propertyNames)
        {
            propertyNames?.ForEach(name => this.RaisePropertyChanged(name));
        }

        /// <summary>
        /// Raises this object's PropertyChanged event.
        /// </summary>
        /// <typeparam name="T">The type of the property that has a new value</typeparam>
        /// <param name="propertyExpression">A Lambda expression representing the property that has a new value.</param>
        protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
        {
            var propertyName = ExpressionHelper.ExtractPropertyName(propertyExpression);
            if (!string.IsNullOrWhiteSpace(propertyName))
            {
                this.RaisePropertyChanged(propertyName);
            }
        }

        /// <summary>
        ///
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="storage"></param>
        /// <param name="value"></param>
        /// <param name="issameraise"> 值相同时是否触发通知 </param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        protected virtual bool SetProperty<T>(ref T storage, T value, bool issameraise = false)
        {
            if (object.Equals(storage, value) && issameraise)
            {
                return false;
            }

            storage = value;

            var trace = new StackTrace();
            var methodName = trace.GetFrame(1).GetMethod();
            if (methodName.Name.StartsWith("set_"))
            {
                var propertyName = methodName.Name.Remove(0, 4);
                if (!string.IsNullOrWhiteSpace(propertyName))
                {
                    this.RaisePropertyChanged(propertyName);
                }
            }
            return true;
        }
    }
}